//
// Created by tang on 2022/3/30.
//

#include "gpio.hpp"

#include <pigpio.h>
#include <cassert>

Pin::Pin(uint8_t number, uint8_t mode): pin_(number), mode_(mode & PM_INPUT ? mode : (mode & 0x0f)) {
    gpioSetMode(pin_, mode_ & PM_INPUT ? PI_INPUT : PI_OUTPUT);
    if (mode_ & PM_INPUT)
        switch (mode_ & 0xF0) {
            case PM_PULL_NONE:
                gpioSetPullUpDown(pin_, PI_OFF);
                break;
            case PM_PULL_UP:
                gpioSetPullUpDown(pin_, PI_PUD_UP);
                break;
            case PM_PULL_DOWN:
                gpioSetPullUpDown(pin_, PI_PUD_DOWN);
                break;
        }
}

Pin::~Pin() = default;

bool Pin::toggle() const {
    assert ((mode_ & 0x0F) == PM_OUTPUT);

    int level = gpioRead(pin_);

    assert (level >= 0); //小于 0 是错误

    level = (level == PI_HIGH) ? PI_LOW : PI_HIGH;

    gpioWrite(pin_, level);

    return level == PI_HIGH;
}

void Pin::set(bool high) const {
    assert ((mode_ & 0x0F) == PM_OUTPUT);
    gpioWrite(pin_, high ? PI_HIGH : PI_LOW);
}

Pulse::Pulse(uint8_t pin, uint32_t frequency, double def_duty): pin_(pin) {
    // init
    gpioSetPWMrange(pin_, 255);
    gpioSetPWMfrequency(pin_, frequency);
    gpioPWM(pin_, static_cast<uint32_t>(def_duty * 255));
}

Pulse::~Pulse() {
    gpioPWM(pin_, 0);
}

int Pulse::Frequency() const {
    return gpioGetPWMfrequency(pin_);
}

double Pulse::Duty() const {
    return gpioGetPWMdutycycle(pin_) / 255.0;
}

int Pulse::SetFrequency(uint32_t frequency) const {
    return gpioSetPWMfrequency(pin_, frequency);
}

double Pulse::SetDuty(double duty) const {
    return gpioPWM(pin_, static_cast<uint32_t>(duty * 255)) / 255.0;
}
